package edu.gatech.cc.hwa.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import edu.gatech.cc.hwa.server.features.BrowserFeature;
import edu.gatech.cc.hwa.server.features.IpAddressFeature;
import edu.gatech.cc.hwa.server.features.OperatingSystemFeature;
import edu.gatech.cc.hwa.server.features.TimeToTypePasswordFeature;
import edu.gatech.cc.hwa.server.security.Authenticator;
import edu.gatech.cc.hwa.server.security.exceptions.HwaSecurityException;

public class HardenedPasswordServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	
	private static final String ALLOW = "Allow";
	private static final String DENY = "Deny";

	public void doPost(HttpServletRequest request, HttpServletResponse response) {
		
	}
	
	public void doGet(HttpServletRequest request, HttpServletResponse response) {
		boolean result = false;
		try {
			AuthenticationParameters params = collectParameters(request);
			result = Authenticator.authenticate(params);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (HwaSecurityException e) {
			e.printStackTrace();
		}
		
		//write response
		response.setContentType("text/xml");
		PrintWriter out = null;
		try {
			out = response.getWriter();
			out.println((result) ? ALLOW : DENY);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

	private String readPostData(HttpServletRequest request) throws IOException {
		BufferedReader reader = request.getReader();
		StringBuilder sb = new StringBuilder();
		String line = reader.readLine();
		while (line != null) {
			sb.append(line + "\n");
			line = reader.readLine();
		}
		reader.close();
		return sb.toString();
	}

	private AuthenticationParameters collectParameters(HttpServletRequest request) throws IOException {
		
		String xmlRecords = readPostData(request);
		
		AuthenticationParameters authParam;
		
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
	        DocumentBuilder db = dbf.newDocumentBuilder();
	        InputSource is = new InputSource();
	        is.setCharacterStream(new StringReader(xmlRecords));

	        Document doc = db.parse(is);
	        NodeList nodes = doc.getElementsByTagName("login");

	        // iterate the login data (if many)        
			Element element = (Element) nodes.item(0);
			String name = getCharacterDataFromElementTagName(element, "name");
			String password = getCharacterDataFromElementTagName(element, "password");
			String browserName = getCharacterDataFromElementTagName(element, "browser");
			String browserVersion = getCharacterDataFromElementTagName(element, "browserVersion");
			String platform = getCharacterDataFromElementTagName(element, "platform");
			String passWordTime = getCharacterDataFromElementTagName(element, "passWordTime");
			String ipAddress = getCharacterDataFromElementTagName(element, "ip");
			
			authParam = new AuthenticationParameters(name, 
					password,
					new BrowserFeature(browserName, browserVersion), 
					new OperatingSystemFeature(platform), 
					new TimeToTypePasswordFeature(passWordTime), 
					new IpAddressFeature(ipAddress));
//			return null;
			return authParam;
	    }
	    catch (Exception e) {
	        e.printStackTrace();
	    }
		return null;
	}
	
	private String getCharacterDataFromElementTagName(Element element, String tag) {
		NodeList name = element.getElementsByTagName(tag);
        Element line = (Element) name.item(0);
        
	    Node child = line.getFirstChild();
	    if (child instanceof CharacterData) {
	       CharacterData cd = (CharacterData) child;
	       return cd.getData();
	    }
	    
	    return "?";
	  }
}
